import * as THREE from "three";
import * as TWEEN from "@tweenjs/tween.js";
import { loadGLTF } from "../loader";


export class Library {
  model = "./model/world.glb";
  scene: any;
  camera: any;
  controls: any;
  controls2: any;
  tweenPosition: any;
  tweenRotation: any;
  flag: boolean;
  worldOctree: any;

  constructor(scene: any, camera: any, controls?: any, controls2?: any) {
    this.scene = scene;
    this.camera = camera;
    this.controls = controls;
    this.controls2 = controls2;

    this.tweenPosition = null;
    this.tweenRotation = null;

    this.flag = false; //控制来回修改top

    //加载模型
    this.loadModel();
    //添加事件
    // this.addWheel();
    // this.addClick();
    // this.addkeyBoard();
  }
  getBoundingBox(group) {
    // 创建一个空的边界框
    let groupBoundingBox = new THREE.Box3();
    group.children.forEach((child) => {
      // 将子对象的边界框合并到总的边界框中
      if (child instanceof THREE.Mesh) {
        child.geometry.computeBoundingBox();
        groupBoundingBox.union(
          //从平面局部坐标系转为世界坐标系
          child.geometry.boundingBox.clone().applyMatrix4(child.matrixWorld)
        );
      }
    });

    // 获取合并后的边界框的最小和最大点
    let min = groupBoundingBox.min;
    let max = groupBoundingBox.max;

    console.log("Group对象的边界框最小点:", min);
    console.log("Group对象的边界框最大点:", max);
  }
  loadModel() {
    this.clearStatus();
    // 加载模型，并渲染到画布上
    loadGLTF(this.model).then((object: any) => {
      console.log(object.scene); // 返回组对象Group
      this.getBoundingBox(object.scene);
      // this.setMountain(); //围挡
      this.scene.add(object.scene);
      // 遍历场景中的所有几何体数据
      object.scene.traverse((child: any) => {
        // console.log(child);
        if (child.isMesh) {
          child.castShadow = true;
          child.receiveShadow = true;
        }
      });
    });
  }
  clearStatus() {
    //清空场景状态（相机归位）
    this.camera.lookAt(0, 0, 0);
  }
  start(delta: any) {
    // 更新方法
    if (this.tweenPosition && this.tweenRotation) {
      this.tweenPosition.update();
      this.tweenRotation.update();
    }
  }
  addClick() {
    //使拖拽不会触发聚焦
    let flag = true;
    document.onmousedown = () => {
      flag = true;
      // this.controls.enabled = true;//第一人称控制器

      document.onmousemove = () => {
        flag = false;
      };
    };

    document.onmouseup = (event) => {
      if (flag) {
        this.clickEvent(event);
      }
      // this.controls.enabled = false;//第一人称控制器
      document.onmousemove = null;
    };
  }
  clickEvent(event: MouseEvent) {
    // 获取到浏览器坐标
    const x = (event.clientX / window.innerWidth) * 2 - 1;
    const y = -(event.clientY / window.innerHeight) * 2 + 1;

    // 创建设备坐标（三维）
    const standardVector = new THREE.Vector3(x, y, 0.5);
    // 转化为世界坐标
    const worldVector = standardVector.unproject(this.camera);

    // 做序列化
    const ray = worldVector.sub(this.camera.position).normalize();

    // 如何实现点击选中
    // 创建一个射线发射器，用来发射一条射线
    const raycaster = new THREE.Raycaster(this.camera.position, ray);

    // 返回射线碰撞到的物体
    const intersects = raycaster.intersectObjects(this.scene.children, true);

    if (this.tweenPosition) this.tweenPosition = null;
    let point3d: any = null;
    if (intersects.length) {
      point3d = intersects[0];
      // console.log(point3d);
    }
    if (point3d) {
      const proportion = 3; //倍数
      // 开始动画来修改观察点
      const time = 1000;
      // 位置
      this.tweenPosition = new TWEEN.Tween(this.camera.position)
        .to(
          {
            x: point3d.point.x * proportion,
            y: point3d.point.y * proportion,
            z: point3d.point.z * proportion,
          },
          time
        )
        .start();
      // 方向
      this.tweenRotation = new TWEEN.Tween(this.camera.rotation)
        .to(
          {
            x: this.camera.rotation.x,
            y: this.camera.rotation.y,
            z: this.camera.rotation.z,
          },
          time
        )
        .start();
    }
  }
  addWheel() {
    //让场景根据鼠标位置进行缩放
    let that = this;
    //@ts-ignore
    document.onmousewheel = function (e) {
      var e = e || window.event;

      const value = 30;

      //获取鼠标坐标位置
      const x = (e.clientX / window.innerWidth) * 2 - 1;
      const y = -(e.clientY / window.innerHeight) * 2 + 1;

      // 获取屏幕坐标
      const vector = new THREE.Vector3(x, y, 0.5);
      // 将屏幕坐标转换为three.js场景坐标（鼠标点击位坐标置转三维坐标）
      vector.unproject(that.camera);
      // 获取缩放的坐标信息
      vector.sub(that.camera.position).normalize();

      if (e.wheelDelta > 0) {
        //针对相机做处理
        that.camera.position.x += vector.x * value;
        that.camera.position.y += vector.y * value;
        that.camera.position.z += vector.z * value;
        that.controls.target.x += vector.x * value;
        that.controls.target.y += vector.y * value;
        that.controls.target.z += vector.z * value;
      } else {
        that.camera.position.x -= vector.x * value;
        that.camera.position.y -= vector.y * value;
        that.camera.position.z -= vector.z * value;
        that.controls.target.x -= vector.x * value;
        that.controls.target.y -= vector.y * value;
        that.controls.target.z -= vector.z * value;
      }
    };
  }
  addkeyBoard() {
    document.onkeydown = (e: any) => {
      this.keyBoardEvent(e);
    };
    // document.onkeyup = (e: any) => {
    //   this.keyBoardEvent(e);
    // };
  }
  keyBoardEvent(e) {
    if (this.controls2) {
      //指针控制器
      switch (e.keyCode) {
        case 38: // up
        case 87: // w
          this.controls2.moveForward(1);
          break;
        case 37: // left
        case 65: // a
          this.controls2.moveRight(-1);
          break;
        case 40: // down
        case 83: // s
          this.controls2.moveForward(-1);
          break;
        case 39: // right
        case 68: // d
          this.controls2.moveRight(1);
          break;
      }
    } else {
      //用户前进视点，这里选择屏幕面上的点
      let lookPoint = new THREE.Vector2();
      lookPoint.x = window.innerWidth / 2;
      lookPoint.y = window.innerHeight / 2;
      //1、通过射线获取视线
      const raycaster = new THREE.Raycaster();
      //2、计算相机的当前位置和目标位置
      let currentCameraPosition = this.camera.position.clone();
      //与xy平面平行的平面
      let plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
      // raycaster.ray用于进行光线投影，给平面plane进行投影
      let intersectionPoint = new THREE.Vector3(); //用于存储交点
      let targetPosition = raycaster.ray.intersectPlane(
        plane,
        intersectionPoint
      );
      // targetPosition.set(targetPosition.x,currentCameraPosition.y,targetPosition.z);
      this.controls.target.copy(targetPosition);
      //3、计算相机移动的向量,sub向量减法
      let moveVector = targetPosition.sub(currentCameraPosition); //从 currentCameraPosition 指向 targetPosition
      let directionVector = moveVector.normalize();
      console.log("目标点", targetPosition);
      console.log("相机", currentCameraPosition);
      console.log("移动距离", moveVector.length());
      console.log("移动方向", directionVector);
      this.addRayHelper(this.camera.position, targetPosition, directionVector);

      //4、移动相机
      let moveSpeed = 1;
      let newPosition = new THREE.Vector3();

      //轨迹控制器
      switch (e.keyCode) {
        case 38: // up
        case 87: // w
          newPosition = currentCameraPosition.add(
            moveVector.multiplyScalar(moveSpeed)
          );
          this.camera.position.copy(newPosition);
          break;
        case 37: // left
        case 65: // a
          targetPosition.copy({
            x: this.controls.target.x - 1,
            y: this.controls.target.y,
            z: this.controls.target.z,
          });
          this.controls.target.copy(targetPosition);
          break;
        case 40: // down
        case 83: // s
          newPosition = currentCameraPosition.sub(
            moveVector.multiplyScalar(moveSpeed)
          );
          this.camera.position.copy(newPosition);
          this.controls.target.copy(targetPosition);
          break;
        case 39: // right
        case 68: // d
          targetPosition.copy({
            x: this.controls.target.x + 1,
            y: this.controls.target.y,
            z: this.controls.target.z,
          });
          this.controls.target.copy(targetPosition);
          break;
      }
    }
  }
  addRayHelper(origin, target, directionVector) {
    // let planeHelper = new THREE.Mesh(
    //   new THREE.PlaneGeometry(100, 100),
    //   new THREE.MeshBasicMaterial({ color: 0xff00ff, side: THREE.DoubleSide })
    // );
    // planeHelper.position.copy(origin);
    // // 计算旋转角度
    // let planeNormal  = new THREE.Vector3(0, 0, -1); //z轴，plane的法向量
    // let angle = Math.acos(planeNormal.dot(directionVector)); // 计算方向向量与上向量之间的夹角
    // // 将角度转换为弧度
    // let angleInDegrees = THREE.MathUtils.radToDeg(angle);
    // // 计算旋转轴
    // let rotationAxis = new THREE.Vector3();
    // rotationAxis.crossVectors(planeNormal,directionVector).normalize(); // 使用叉积计算旋转轴
    // planeHelper.rotateOnWorldAxis(rotationAxis, angleInDegrees);
    // this.scene.add(planeHelper);
    let originHelper = new THREE.Mesh(
      new THREE.SphereGeometry(0.3),
      new THREE.MeshBasicMaterial({ color: 0x00ffff })
    );
    originHelper.position.copy(origin);
    this.scene.add(originHelper);
    let targetHelper = new THREE.Mesh(
      new THREE.SphereGeometry(0.3),
      new THREE.MeshBasicMaterial({ color: 0x00ff00 })
    );
    targetHelper.position.copy(target);
    this.scene.add(targetHelper);
    // 创建线的几何体，从射线的起点到一个确定的终点
    let geometry = new THREE.BufferGeometry().setFromPoints([origin, target]);
    // 创建线的材质，可以选择颜色
    let material = new THREE.LineBasicMaterial({ color: 0xff0000 });
    // 创建线对象
    let line = new THREE.Line(geometry, material);
    // 将线对象添加到场景中
    this.scene.add(line);
  }
  //围挡
  setMountain() {
    const textureLoader = new THREE.TextureLoader();
    const map = textureLoader.load("./img/modelBg2.jpg");
    const cylinderGeometry = new THREE.CylinderGeometry(160, 160, 800, 32);
    const cylinderMaterial = new THREE.MeshBasicMaterial({
      side: THREE.BackSide,
      map: map,
    });
    let cylinder = new THREE.Mesh(cylinderGeometry, cylinderMaterial);
    cylinder.position.set(0, -2.8, 0);
    cylinder.rotation.y = Math.PI * 0.9;

    this.scene.add(cylinder);
  }
}
